﻿(function ($) {
    var methods = {
        alert: function (promptText, promptPosition) {
            var options = methods._getOptions();
            if (promptPosition) options.promptPosition = promptPosition;
            methods._showPrompt(this, promptText, "alert", options);
            return this;
        },
        info: function (promptText,promptPosition){
            var options = methods._getOptions();
            if (promptPosition) options.promptPosition = promptPosition;
            methods._showPrompt(this, promptText, "info", options);
            return this;
        },
        load: function (promptText,promptPosition){
            var options = methods._getOptions();
            if (promptPosition) options.promptPosition = promptPosition;
            methods._showPrompt(this, promptText, "load", options);
            return this;
        },
        /**
        * Closes the prompt associated with the given field
        * 
        * @param {jqObject}
        *            field
        */
        _close: function (field) {      
            var prompt = methods._getPrompt(field);
            if (prompt)
                prompt.fadeTo("fast", 0, function () {
                    prompt.remove();
                });
        },
        /**
        * Closes all prompts on the page
        */
        _closeAll: function () {
            $('.formError').fadeTo("fast", 0.3, function () {
                $(this).remove();
            });
        },
        close: function (field) {
            if(field.length>0){
                return methods._close(field[0]);
            }else {
                return methods._closeAll();
            }
        },
        /**
        * Kind of the constructor, called before any action
        * @param {Map} user options
        */
        _init: function (options) {
            var body = $(document.body);
            if (!body.data('jqp') || body.data('jqp') == null) {
                methods._saveOptions(body, options);

                // bind all formError elements to close on click
                $(".formError").live("click", function () {
                    $(this).fadeOut(150, function () {

                        // remove prompt once invisible
                        $(this).remove();
                    });
                });
            }
        },
        _getOptions: function () {
            return $(document.body).data('jqp');
        },

        /**
        * Builds or updates a prompt with the given information
        *
        * @param {jqObject} field
        * @param {String} promptText html text to display type
        * @param {String} type the type of bubble: 'info' (green), 'load' (black) anything else (red)
        * @param {Map} options user options
        */
        _showPrompt: function (field, promptText, type, options) {
            var prompt = methods._getPrompt(field);
            if (prompt)
                methods._updatePrompt(field, prompt, promptText, type, options);
            else
                methods._buildPrompt(field, promptText, type, options);
        },
        /**
        * Builds and shades a prompt for the given field.
        *
        * @param {jqObject} field
        * @param {String} promptText html text to display type
        * @param {String} type the type of bubble: 'info' (green), 'load' (black) anything else (red)
        * @param {Map} options user options
        */
        _buildPrompt: function (field, promptText, type, options) {

            // create the prompt
            var prompt = $('<div>');

            prompt.addClass(methods._getClassName(field.attr("id")) + "formError");
            prompt.addClass("formError");

            switch (type) {
                case "info":
                    prompt.addClass("greenPopup");
                    break;
                case "load":
                    prompt.addClass("blackPopup");
            }

            // create the prompt content
            var promptContent = $('<div>').addClass("formErrorContent").html(promptText).appendTo(prompt);
            // create the css arrow pointing at the field
            // note that there is no triangle on max-checkbox and radio
            if (options.showArrow) {
                var arrow = $('<div>').addClass("formErrorArrow");

                switch (options.promptPosition) {
                    case "bottomLeft":
                    case "bottomRight":
                        prompt.find(".formErrorContent").before(arrow);
                        arrow.addClass("formErrorArrowBottom").html('<div class="line1"><!-- --></div><div class="line2"><!-- --></div><div class="line3"><!-- --></div><div class="line4"><!-- --></div><div class="line5"><!-- --></div><div class="line6"><!-- --></div><div class="line7"><!-- --></div><div class="line8"><!-- --></div><div class="line9"><!-- --></div><div class="line10"><!-- --></div>');
                        break;
                    case "topLeft":
                    case "topRight":
                        arrow.html('<div class="line10"><!-- --></div><div class="line9"><!-- --></div><div class="line8"><!-- --></div><div class="line7"><!-- --></div><div class="line6"><!-- --></div><div class="line5"><!-- --></div><div class="line4"><!-- --></div><div class="line3"><!-- --></div><div class="line2"><!-- --></div><div class="line1"><!-- --></div>');
                        prompt.append(arrow);
                        break;
                }
            }

            //Cedric: Needed if a container is in position:relative
            // insert prompt in the form or in the overflown container?
            if (options.isOverflown)
                field.before(prompt);
            else
                $("body").append(prompt);

            var pos = methods._calculatePosition(field, prompt, options);
            prompt.css({
                "top": pos.callerTopPosition,
                "left": pos.callerleftPosition,
                "marginTop": pos.marginTopSize,
                "opacity": 0
            });

            return prompt.animate({
                "opacity": 0.87
            });

        },
        /**
        * Updates the prompt text field - the field for which the prompt
        * @param {jqObject} field
        * @param {String} promptText html text to display type
        * @param {String} type the type of bubble: 'info' (green), 'load' (black) anything else (red)
        * @param {Map} options user options
        */
        _updatePrompt: function (field, prompt, promptText, type, options) {

            if (prompt) {
                if (type == "info")
                    prompt.addClass("greenPopup");
                else
                    prompt.removeClass("greenPopup");

                if (type == "load")
                    prompt.addClass("blackPopup");
                else
                    prompt.removeClass("blackPopup");


                prompt.find(".formErrorContent").html(promptText);

                var pos = methods._calculatePosition(field, prompt, options);
                prompt.animate({
                    "top": pos.callerTopPosition,
                    "marginTop": pos.marginTopSize
                });
            }
        },

        /**
        * Returns the error prompt matching the field if any
        *
        * @param {jqObject}
        *            field
        * @return undefined or the error prompt (jqObject)
        */
        _getPrompt: function (field) {
            var id = field.attr("id");
            if(id == undefined) field.attr("id",new Date().getMilliseconds());
            var className = "." + methods._getClassName(field.attr("id")) + "formError";
            var match = $(className)[0];
            if (match)
                return $(match);
        },
        /**
        * Calculates prompt position
        *
        * @param {jqObject}
        *            field
        * @param {jqObject}
        *            the prompt
        * @param {Map}
        *            options
        * @return positions
        */
        _calculatePosition: function (field, promptElmt, options) {

            var promptTopPosition, promptleftPosition, marginTopSize;
            var fieldWidth = field.width();
            var promptHeight = promptElmt.height();

            var overflow = options.isOverflown;
            if (overflow) {
                // is the form contained in an overflown container?
                promptTopPosition = promptleftPosition = 0;
                // compensation for the arrow
                marginTopSize = -promptHeight;
            } else {
                var offset = field.offset();
                promptTopPosition = offset.top;
                promptleftPosition = offset.left;
                marginTopSize = 0;
            }

            switch (options.promptPosition) {

                default:
                case "topRight":
                    if (overflow)
                    // Is the form contained in an overflown container?
                        promptleftPosition += fieldWidth - 30;
                    else {
                        promptleftPosition += fieldWidth - 30;
                        promptTopPosition += -promptHeight;
                    }
                    break;
                case "topLeft":
                    promptTopPosition += -promptHeight - 10;
                    break;
                case "centerRight":
                    promptleftPosition += fieldWidth + 13;
                    break;
                case "bottomLeft":
                    promptTopPosition = promptTopPosition + field.height() + 15;
                    break;
                case "bottomRight":
                    promptleftPosition += fieldWidth - 30;
                    promptTopPosition += field.height() + 5;
            }

            return {
                "callerTopPosition": promptTopPosition + "px",
                "callerleftPosition": promptleftPosition + "px",
                "marginTopSize": marginTopSize + "px"
            };
        },
        /**
        * Saves the user options and variables in the form.
        */
        _saveOptions: function (body, options) {
            var userOptions = $.extend({
                promptPosition: "centerRight",
                // Used when the form is displayed within a scrolling DIV
                isOverflown: false,
                overflownDIV: "",
                showArrow: false
            },options);
            body.data('jqp', userOptions);
            return userOptions;
        },

        /**
        * Removes forbidden characters from class name
        * @param {String} className
        */
        _getClassName: function (className) {
            return className.replace(":", "_").replace(".", "_");
        }
    };

    /**
    * Plugin entry point.        
    */
    $.fn.prompt = function (method) {
        var field = $(this);
        if (typeof (method) == 'string' && method.charAt(0) != '_' && methods[method]) {
            methods._init();
            return methods[method].apply(field, Array.prototype.slice.call(arguments, 1));
        } else if (typeof method == 'object' || !method) {
            return methods._init(arguments);
        } else {
            $.error('Method ' + method + ' does not exist in jQuery.prompt');
        }
    };
    $.prompt = function (method) {
        if (typeof (method) == 'string' && method.charAt(0) != '_' && methods[method]) {
            return methods[method](Array.prototype.slice.call(arguments, 1));
        } else {
            $.error('Method ' + method + ' does not exist in jQuery.prompt');
        }
    };

})(jQuery);
